package service

import (
	"crypto/md5"
	"errors"
	"fmt"
	"go-admin/internal/model"
	mr "go-admin/internal/model/api/model_request"
	ms "go-admin/internal/model/api/model_response"
	"go-admin/pkg/app"
)

func (s *Service) CreateUser(param *mr.CreateUserRequest) (string, error) {
	// 判断用户是否存在
	user, err := s.dao.GetUserByUserName(param.Username)
	if err != nil {
		return user.Id, err
	}
	// 判断是否存在
	if user.Id != "" {
		return user.Id, errors.New("用户已存在")
	}
	// 开启事务
	tx := s.dao.Engine.Begin()
	// 插入用户表
	insertId, err := s.dao.CreateUser(tx, param)
	if err != nil {
		tx.Rollback()
		return insertId, err
	}
	// 插入用户角色中间表
	if err = s.dao.CreateUserRole(tx, insertId, param.RoleIds); err != nil {
		tx.Rollback()
		return insertId, err
	}
	// 根据角色ids获取角色
	roles, err := s.dao.GetRolesByRoleIds(param.RoleIds)
	if err != nil {
		tx.Rollback()
		return insertId, err
	}
	// 将用户与角色添加到casbin中
	if err = s.dao.CreateCasbinUserRole(tx, "g", param.Username, roles); err != nil {
		tx.Rollback()
		return insertId, err
	}
	tx.Commit()
	return insertId, nil
}

func (s *Service) CountUser(param *mr.ListUserRequest) (int, error) {
	return s.dao.CountUser(param)
}

func (s *Service) GetUserList(param *mr.ListUserRequest, pager *app.Pager) ([]*model.User, error) {
	return s.dao.GetUserList(param, pager.PageIndex, pager.PageSize)
}

func (s *Service) GetUserById(id string) (*ms.UserDetailResponse, error) {
	user, err := s.dao.GetUserById(id)
	if err != nil {
		return nil, err
	}
	// 判断是否存在
	if user.Id == "" {
		return nil, err
	}
	// 获取角色id绑定的菜单
	roleMenuIds, err := s.dao.GetRoleIdsByUserId(id)
	if err != nil {
		return nil, err
	}
	res := ms.ModelToDetailUserRes(user, toRoleIdsList(roleMenuIds))
	return res, nil
}

func toRoleIdsList(userRoles []*model.UserRole) []string {
	roleIds := make([]string, 0)
	for _, v := range userRoles {
		roleIds = append(roleIds, v.RoleId)
	}
	return roleIds
}

func (s *Service) UpdateUser(param *mr.UpdateUserRequest) error {
	// 开启事务
	tx := s.dao.Engine.Begin()
	// 更新用户表
	if err := s.dao.UpdateUser(tx, param); err != nil {
		tx.Rollback()
		return err
	}
	// 删除用户绑定的角色
	if err := s.dao.DeleteUserRolesS(tx, param.Id); err != nil {
		tx.Rollback()
		return err
	}
	// 添加用户绑定的角色
	if err := s.dao.CreateUserRole(tx, param.Id, param.RoleIds); err != nil {
		tx.Rollback()
		return err
	}
	// 根据角色ids获取角色
	roles, err := s.dao.GetRolesByRoleIds(param.RoleIds)
	if err != nil {
		tx.Rollback()
		return err
	}
	// 删除用户与角色在casbin中
	if err = s.dao.DeleteCasbinUserRole(tx, "g", param.Username); err != nil {
		tx.Rollback()
		return err
	}
	// 将用户与角色添加到casbin中
	if err = s.dao.CreateCasbinUserRole(tx, "g", param.Username, roles); err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func (s *Service) DeleteUserS(ids []string) error {
	return s.dao.DeleteUserS(ids)
}

// 用户密码登录
func (s *Service) LoginByPassword(param *mr.LoginByPasswordRequest) (interface{}, error) {
	// 根据用户获取密码
	user, err := s.dao.GetUserByUserName(param.Username)
	if err != nil {
		return nil, errors.New("登录失败")
	}
	// 判断是否存在
	if user.Id == "" {
		return nil, errors.New("用户不存在")
	}
	// 判断账号和密码是否相等
	if fmt.Sprintf("%x", md5.Sum([]byte(param.Password))) != user.Password {
		return nil, errors.New("用户或密码不正确")
	}
	// 获取用户的角色列表
	roles, err := s.dao.GetRolesByUserName(user.Username)
	if err != nil {
		return nil, errors.New("登录失败")
	}
	roleKey := make([]string, 0)
	for _, v := range roles {
		roleKey = append(roleKey, v.RoleKey)
	}
	// 生成token和刷新token
	token, _ := app.GenToken(user.Username, roleKey)
	refreshToken, _ := app.GenRefreshToken(user.Username, roleKey)
	m := map[string]interface{}{
		"token":        token,
		"refreshToken": refreshToken,
	}
	return m, nil
}

// 用户密码登录
func (s *Service) GetTokenByRefreshToken(username string) (interface{}, error) {
	// 根据用户获取密码
	user, err := s.dao.GetUserByUserName(username)
	if err != nil {
		return nil, errors.New("登录失败")
	}
	// 判断是否存在
	if user.Id == "" {
		return nil, errors.New("用户不存在")
	}
	// 获取用户的角色列表
	roles, err := s.dao.GetRolesByUserName(user.Username)
	if err != nil {
		return nil, errors.New("获取失败")
	}
	roleKey := make([]string, 0)
	for _, v := range roles {
		roleKey = append(roleKey, v.RoleKey)
	}
	// 生成token和刷新token
	token, _ := app.GenToken(user.Username, roleKey)
	refreshToken, _ := app.GenRefreshToken(user.Username, roleKey)
	m := map[string]interface{}{
		"token":        token,
		"refreshToken": refreshToken,
	}
	return m, nil
}

// 根据用户token获取用户信息
func (s *Service) GetUserInfo(username string) (ms.UserInfo, error) {
	userInfo := new(ms.UserInfo)
	// 根据用户获取密码
	user, err := s.dao.GetUserByUserName(username)
	if err != nil {
		return *userInfo, err
	}
	userInfo.Email = user.Email
	userInfo.Gender = user.Gender
	userInfo.Avatar = user.Avatar
	userInfo.Phone = user.Phone
	userInfo.RealName = user.RealName
	// 根据用户的部门id获取所属部门
	dept, err := s.dao.GetDeptById(user.DeptId)
	if err != nil {
		return *userInfo, err
	}
	userInfo.DeptName = dept.DeptName
	job, err := s.dao.GetJobById(user.JobId)
	if err != nil {
		return *userInfo, err
	}
	userInfo.JobName = job.JobName
	// 根据用户信息获取所有的角色
	// 获取用户的角色列表
	roles, err := s.dao.GetRolesByUserName(user.Username)
	if err != nil {
		return *userInfo, err
	}
	roleKey := make([]string, 0)
	for _, v := range roles {
		roleKey = append(roleKey, v.RoleKey)
	}
	userInfo.RoleKey = roleKey
	return *userInfo, nil
}
